// 1.11 获取串流令牌(getStreamToken)
// 因为只使用本地串流,因此该文件只获取xhome
use anyhow::{Result,anyhow};
use serde_json;
use chrono::{DateTime, Utc, Duration};
use std::str::FromStr;
use serde::{Serialize, Deserialize};
use reqwest::Client;
use crate::db::{db_select::db_select, db_insert::db_insert};
use crate::api::get_xsts::get_xsts_stream_token;
use serde_json::Value;

/* payload的结构体 */
#[derive(Serialize, Deserialize, Debug)]
struct payload{
    token: String,
    offeringId: String,
}
/* response的结构体 */
#[derive(Debug, Serialize, Deserialize)]
struct Response {
    offeringSettings: OfferingSettings,
    market: String,
    gsToken: String,
    tokenType: String,
    durationInSeconds: i64,
}

#[derive(Debug, Serialize, Deserialize)]
struct OfferingSettings {
    allowRegionSelection: bool,
    regions: Vec<Region>,
    selectableServerTypes: Option<Value>,
    clientCloudSettings: ClientCloudSettings,
}

#[derive(Debug, Serialize, Deserialize)]
struct Region {
    name: String,
    baseUri: String,
    networkTestHostname: Option<String>,
    isDefault: bool,
    systemUpdateGroups: Option<Value>,
    fallbackPriority: i32,
}

#[derive(Debug, Serialize, Deserialize)]
struct ClientCloudSettings {
    Environments: Vec<Environment>,
}

#[derive(Debug, Serialize, Deserialize)]
struct Environment {
    Name: String,
    AuthBaseUri: Option<String>,
}

pub async fn get_stream_token() -> Result<String> {

    {
        // 检查数据库中的stream_token是否存在且未过期
        if let Ok(config) = db_select("stream_token_not_after").await {
            let expiry:DateTime<Utc> = DateTime::from_str(&config.value).expect("invalid datetime format");
            let now = Utc::now();
            if(now < expiry){
                // 没过期，直接返回
                return Ok(db_select("stream_token").await.unwrap().value);
            }
        }
    }
    
    let payload = payload{
        token: get_xsts_stream_token().await.unwrap(),
        offeringId: "xhome".to_string(),
    };

    let payload = serde_json::to_string(&payload).unwrap();
    println!("get_stream_token payload: {}", payload);
    println!("get_stream_token payload's length: {}", payload.len());
    
    let client = Client::new();
    let response = client.post("https://xhome.gssv-play-prod.xboxlive.com/v2/login/user")
        .header("Content-Type", "application/json")
        .header("Cache-Control", "no-store, must-revalidate, no-cache")
        .header("x-gssv-client", "XboxComBrowser")
        .header("Content-Length", payload.len())
        .body(payload)
        .send().await.unwrap();

    let response_code = response.status().as_u16();
    let response_text = response.text().await.unwrap();


    match response_code {
        200 => {
            let response:Response = serde_json::from_str(&response_text).unwrap();

            let now = Utc::now();
            let not_after = now + Duration::seconds(response.durationInSeconds);
            let stream_token_not_after = not_after.to_rfc3339();

            db_insert("stream_token", &response.gsToken).await.unwrap();
            db_insert("stream_token_not_after", &stream_token_not_after).await.unwrap();
            return Ok(response.gsToken);
        }
        _ => {
            return Err(anyhow!("stream_token fail to get, status code:{}", response_code));
        }
    }

}